#include "UUID.h"
#include "lang/String.h"
#include "array/Array.hpp"
using namespace yzrilyzr_lang;
namespace yzrilyzr_util{
	UUID::UUID(const yzrilyzr_array::ByteArray & array){
		msb=(static_cast<uint64_t>(array[0] & 0xff) << 56)
		|(static_cast<uint64_t>(array[1] & 0xff) << 48)
		|(static_cast<uint64_t>(array[2] & 0xff) << 40)
		|(static_cast<uint64_t>(array[3] & 0xff) << 32)
		|(static_cast<uint64_t>(array[4] & 0xff) << 24)
		|(static_cast<uint64_t>(array[5] & 0xff) << 16)
		|(static_cast<uint64_t>(array[6] & 0xff) << 8)
		|(static_cast<uint64_t>(array[7] & 0xff) << 0);
		
		lsb=(static_cast<uint64_t>(array[8] & 0xff) << 56)
		|(static_cast<uint64_t>(array[9] & 0xff) << 48)
		|(static_cast<uint64_t>(array[10] & 0xff) << 40)
		|(static_cast<uint64_t>(array[11] & 0xff) << 32)
		|(static_cast<uint64_t>(array[12] & 0xff) << 24)
		|(static_cast<uint64_t>(array[13] & 0xff) << 16)
		|(static_cast<uint64_t>(array[14] & 0xff) << 8)
		|(static_cast<uint64_t>(array[15] & 0xff) << 0);
		
	}
	String UUID::toString() const{
		char buf[37]; // 36 chars + null terminator
		snprintf(buf, sizeof(buf),
				 "%08x-%04x-%04x-%04x-%012llx",
				 (unsigned int)(msb >> 32),
				 (unsigned int)((msb >> 16) & 0xFFFF),
				 (unsigned int)(msb & 0xFFFF),
				 (unsigned int)(lsb >> 48),
				 (unsigned long long)(lsb & 0xFFFFFFFFFFFF));
		return String(buf);
	}

	int32_t UUID::hashCode() const{
		uint64_t h=msb ^ lsb;
		return std::abs((int32_t)(h ^ (h >> 32)));
	}

	bool UUID::operator==(UUID & v) const{
		return msb == v.msb && lsb == v.lsb;
	}

	UUID UUID::fromString(const String & str){
		if(str.length() != 36) return UUIDs::NULL_UUID;

		auto components=str.split("-");
		if(components.length != 5) return UUIDs::NULL_UUID;

		// Check each component length
		if(components[0].length() != 8 ||
		   components[1].length() != 4 ||
		   components[2].length() != 4 ||
		   components[3].length() != 4 ||
		   components[4].length() != 12){
			return UUIDs::NULL_UUID;
		}

		try{
			uint64_t mostSigBits=std::stoull(components[0].tostring(), nullptr, 16);
			mostSigBits<<=16;
			mostSigBits|=std::stoul(components[1].tostring(), nullptr, 16);
			mostSigBits<<=16;
			mostSigBits|=std::stoul(components[2].tostring(), nullptr, 16);

			uint64_t leastSigBits=std::stoul(components[3].tostring(), nullptr, 16);
			leastSigBits<<=48;
			leastSigBits|=std::stoull(components[4].tostring(), nullptr, 12);

			return UUID{mostSigBits, leastSigBits};
		} catch(...){
			// Catch any parsing errors (invalid hex digits, etc)
			return UUIDs::NULL_UUID;
		}
	}
}